#ifndef __WX_SCOPED_POINTER__
#define __WX_SCOPED_POINTER__

#include "wx/defs.h"

#define wxDEFINE_SCOPED_PTR_TYPE(T)    \
  wxDECLARE_SCOPED_PTR(T, T ## Ptr)  \
  wxDEFINE_SCOPED_PTR(T, T ## Ptr)


#define wxDEFINE_SCOPED_PTR(T, name)  \
  name::~name() {   \
    wxCHECKED_DELETE(m_ptr);   \
  }

#define wxCHECKED_DELETE(ptr)   \
  do {   \
    delete ptr;   \
  } while ( wxFalse )


#define wxCHECKED_DELETE_ARRAY(ptr)   \
  do {   \
    delete [] ptr;   \
  } while ( wxFalse )


#define wxDECLARE_SCOPED_PTR(T, name)   \
  class name {   \
    private:                            \
      T * m_ptr;                      \
      name(name const &);             \
      name & operator=(name const &); \
    public:                             \
      wxEXPLICIT name(T * ptr = NULL) \
        : m_ptr(ptr) { }                \
      ~name();                        \
      void reset(T * ptr = NULL)      \
      {                               \
        if (m_ptr != ptr)           \
        {                           \
          delete m_ptr;           \
          m_ptr = ptr;            \
        }                           \
      }                               \
      T *release()                    \
      {                               \
        T *ptr = m_ptr;             \
        m_ptr = NULL;               \
        return ptr;                 \
      }                               \
      T & operator*() const           \
      {                               \
        wxASSERT(m_ptr != NULL);    \
        return *m_ptr;              \
      }                               \
      T * operator->() const          \
      {                               \
        wxASSERT(m_ptr != NULL);    \
        return m_ptr;               \
      }                               \
      T * get() const                 \
      {                               \
        return m_ptr;               \
      }                               \
      void swap(name & ot)            \
      {                               \
        T * tmp = ot.m_ptr;         \
        ot.m_ptr = m_ptr;           \
        m_ptr = tmp;                \
      }                               \
  };

#define wxDECLARE_SCOPED_ARRAY(T, name)\
  class name {                         \
    private:                            \
      T * m_ptr;                      \
      name(name const &);             \
      name & operator=(name const &); \
    public:                             \
      wxEXPLICIT name(T * p = NULL) : m_ptr(p) \
      {}                              \
      ~name();                        \
      void reset(T * p = NULL);       \
      T & operator[](long int i) const {  \
        wxASSERT(m_ptr != NULL);    \
        wxASSERT(i >= 0);           \
        return m_ptr[i];            \
      }                               \
      T * get() const {                 \
        return m_ptr;               \
      }                               \
      void swap(name & ot) {            \
        T * tmp = ot.m_ptr;         \
        ot.m_ptr = m_ptr;           \
        m_ptr = tmp;                \
      }                               \
  };

#define wxDEFINE_SCOPED_ARRAY(T, name)  \
  name::~name()                           \
  {                                       \
    wxCHECKED_DELETE_ARRAY(m_ptr);      \
  }                                       \
  void name::reset(T * p) {                \
    if (m_ptr != p) {                    \
      wxCHECKED_DELETE_ARRAY(m_ptr);   \
      m_ptr = p;                       \
    }                                   \
  }

#define wxDEFINE_TIED_SCOPED_PTR_TYPE(T)                                      \
  wxDEFINE_SCOPED_PTR_TYPE(T)                                               \
  class T ## TiedPtr : public T ## Ptr                                      \
  {                                                                         \
    public:                                                                   \
      T ## TiedPtr(T **pp, T *p)                                            \
        : T ## Ptr(p), m_pp(pp)                                           \
      {                                                                     \
        m_pOld = *pp;                                                     \
        *pp = p;                                                          \
      }                                                                     \
      \
      ~ T ## TiedPtr()                                                      \
      {                                                                     \
        *m_pp = m_pOld;                                                   \
      }                                                                     \
      \
    private:                                                                  \
      T **m_pp;                                                             \
      T *m_pOld;                                                            \
  };

#endif
